package com.atguigu.seckill.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.atguigu.common.utils.R;
import com.atguigu.seckill.feign.SecKillToCouponService;
import com.atguigu.seckill.feign.SecKillToProductService;
import com.atguigu.seckill.service.SecKillService;
import com.atguigu.seckill.to.SecKillSkuRedisTo;
import com.atguigu.seckill.vo.PmsSkuInfoVo;
import com.atguigu.seckill.vo.SmsSeckillSessionVo;
import com.atguigu.seckill.vo.SmsSeckillSkuRelationVo;
import org.redisson.api.RSemaphore;
import org.redisson.api.RedissonClient;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

@Service
public class SecKillServiceImpl implements SecKillService {

    private final String SESSIONS_CACHE_PREFIX = "seckill:sessions:";
    private final String SKUKILL_CACHE_PREFIX = "seckill:skus";

    private final String SKU_STOCK_SEMAPHORE = "seckill:stock:";//+商品随机码

    @Autowired
    private SecKillToCouponService secKillToCouponService;

    @Autowired
    private SecKillToProductService secKillToProductService;

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private RedissonClient redissonClient;

    /**
     * 上架商品
     */
    public void upSecKillProduct() {
        boolean flag = true;
        //远程调用优惠信息-查看上架的活动以及商品信息
        R r = secKillToCouponService.SecToCoupon();
        if (r.getCode() == 0) {
            List<SmsSeckillSessionVo> smsSeckillSessionVos = r.getData(new TypeReference<List<SmsSeckillSessionVo>>() {
            });
            for (SmsSeckillSessionVo sessionVo : smsSeckillSessionVos) {
                for (SmsSeckillSkuRelationVo relationVo : sessionVo.getRelations()) {
                    //需要远程查询商品的全部信息封装
                    R info = secKillToProductService.info(relationVo.getSkuId());
                    if (info.getCode() == 0) {
                        PmsSkuInfoVo skuInfo = info.getData("pmsSkuInfo", new TypeReference<PmsSkuInfoVo>() {
                        });
                        relationVo.setPmsSkuInfoVo(skuInfo);
                    } else {
                        throw new RuntimeException("远程调用异常");
                    }
                }
            }

            //数据准备就绪--redis中存储
            //两大存储
            // --第一部分存储时间段--对应的商品集合id
            for (SmsSeckillSessionVo vo : smsSeckillSessionVos) {
                //获取key
                long start = vo.getStartTime().getTime();
                long end = vo.getEndTime().getTime();
                String key = SESSIONS_CACHE_PREFIX + start + "_" + end;
                //判断keys是否在redis存在，不可以重复对一个活动进行商品上架
                if (!redisTemplate.hasKey(key)) {
                    flag = false;
                    //收集value--对应的场次--对应的商品
                    List<String> collect = vo.getRelations().stream().map((m) -> {
                        String promotionSessionId = m.getPromotionSessionId().toString();
                        String skuId = m.getSkuId().toString();
                        return promotionSessionId + "-" + skuId;
                    }).collect(Collectors.toList());
                    //存入redis中
                    redisTemplate.opsForList().leftPushAll(key, collect);
                    //设置过期时间--为商品优惠的结束时间
                    redisTemplate.expireAt(key, vo.getEndTime());
                }


            }
            if (!flag) {
                //第二部分将具体的商品存入对应的缓存中--使用hash存储
                BoundHashOperations hashOps = redisTemplate.boundHashOps(SKUKILL_CACHE_PREFIX);
                for (SmsSeckillSessionVo vo : smsSeckillSessionVos) {
                    vo.getRelations().forEach((m) -> {
                        SecKillSkuRedisTo secKillSkuRedisTo = new SecKillSkuRedisTo();
                        BeanUtils.copyProperties(m, secKillSkuRedisTo);
                        secKillSkuRedisTo.setStartTime(vo.getStartTime().getTime());
                        secKillSkuRedisTo.setSeckillCount(m.getSeckillCount().intValue());
                        secKillSkuRedisTo.setSeckillLimit(m.getSeckillLimit().intValue());
                        secKillSkuRedisTo.setEndTime(vo.getEndTime().getTime());
                        secKillSkuRedisTo.setSkuInfo(m.getPmsSkuInfoVo());
                        //生成随机码--存入到每个商品的详细信息中
                        String replace = UUID.randomUUID().toString().replace("-", "");
                        secKillSkuRedisTo.setRandomCode(replace);
                        //将数据存入缓存中
                        //获取key
                        String key = vo.getId() + "_" + m.getSkuId();
                        hashOps.put(key, secKillSkuRedisTo);
                        //获取该商品的token值，将其作为key存入信号量中，值为该商品的数量
                        RSemaphore semaphore = redissonClient.getSemaphore(SKU_STOCK_SEMAPHORE + secKillSkuRedisTo.getRandomCode());
                        semaphore.trySetPermits(secKillSkuRedisTo.getSeckillCount());
                        semaphore.expireAt(vo.getEndTime());
                    });
                }
            }


        }

    }
}
